// Copyright (c) 2019 Spotify AB.
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

import Foundation

/// Parses Swift Function times generated by `swiftc`
/// if you pass the flags `-Xfrontend -debug-time-expression-type-checking`
class SwiftCompilerTypeCheckOptionParser: SwiftCompilerTimeOptionParser {

    private static let compilerFlag = "-debug-time-expression-type-checking"

    func hasCompilerFlag(commandDesc: String) -> Bool {
        commandDesc.range(of: Self.compilerFlag) != nil
    }

    func parse(from commands: [String: Int]) -> [String: [SwiftTypeCheck]] {
        return commands.compactMap { parse(command: $0.key, occurrences: $0.value) }
            .joined().reduce([:]) { (typeChecksPerFile, typeCheckTime)
        -> [String: [SwiftTypeCheck]] in
            var typeChecksPerFile = typeChecksPerFile
            if var typeChecks = typeChecksPerFile[typeCheckTime.file] {
                typeChecks.append(typeCheckTime)
                typeChecksPerFile[typeCheckTime.file] = typeChecks
            } else {
                typeChecksPerFile[typeCheckTime.file] = [typeCheckTime]
            }
            return typeChecksPerFile
        }
    }

    private func parse(command: String, occurrences: Int) -> [SwiftTypeCheck]? {
        return command.components(separatedBy: "\r").compactMap { commandLine in
            // 0.14ms   /users/mnf/project/SomeFile.swift:10:12
            let parts = commandLine.components(separatedBy: "\t")

            guard parts.count == 2 else {
                return nil
            }

            // 0.14ms
            let duration = parseCompileDuration(parts[0])

            // /users/mnf/project/SomeFile.swift:10:12
            let fileAndLocation = parts[1]
            guard let (file, line, column) = parseNameAndLocation(from: fileAndLocation) else {
                return nil
            }

            return SwiftTypeCheck(file: file,
                                  durationMS: duration,
                                  startingLine: line,
                                  startingColumn: column,
                                  occurrences: occurrences)
        }
    }

}
